#include <iostream>
using namespace std;

#include "ThreadPool.h"
#include "WorkerThread.h"
#include "AutoLock.h"
#include "Task.h"
using namespace yazi::thread;

#include "Logger.h"
using namespace yazi::utility;

ThreadPool::ThreadPool(){

}

ThreadPool::~ThreadPool(){

}

void ThreadPool::create(int size){
    if(size <= 0) return;
    AutoLock lock(&m_mutex_idle);
    for(int i = 0; i < size; ++i){
        Thread* thread = new WorkerThread();
        cout << "create thread " << thread << endl;
        m_list_idle.insert(thread);
        thread->start();
    }
}

Thread* ThreadPool::get_idle_thread(){
    AutoLock lock(&m_mutex_idle);
    while (m_list_idle.size() == 0)
        m_cond_idle.wait(&m_mutex_idle);
    return *m_list_idle.begin();
}

int ThreadPool::get_idle_thread_num(){
    AutoLock lock(&m_mutex_idle);
    return m_list_idle.size();
}

int ThreadPool::get_busy_thread_num(){
    AutoLock lock(&m_mutex_busy);
    return m_list_busy.size();
}

void ThreadPool::move_to_busy(Thread* thread){
    m_mutex_busy.lock();
    m_list_busy.insert(thread);
    m_cond_busy.signal();
    m_mutex_busy.unlock();

    m_mutex_idle.lock();
    auto it = m_list_idle.find(thread);
    if (it != m_list_idle.end())
        m_list_idle.erase(it);
    m_cond_idle.signal();
    m_mutex_idle.unlock();
}

void ThreadPool::move_to_idle(Thread* thread){
    m_mutex_idle.lock();
    m_list_idle.insert(thread);
    m_cond_idle.signal();
    m_mutex_idle.unlock();

    m_mutex_busy.lock();
    auto it = m_list_busy.find(thread);
    if(it != m_list_busy.end())
        m_list_busy.erase(it);
    m_cond_busy.signal();
    m_mutex_busy.unlock();
}

void ThreadPool::assign(Task* task){
    if(task == nullptr){
        std::cerr << "assign a empty task to ThreadPool" << std::endl;
        return;
    }
    Thread* thread = get_idle_thread();
    if(thread == nullptr){
        std::cerr << "thread is nullptr, assign a task failed" << std::endl;
        return;
    }
    std::cout << "assign a new task " << task << " to ThreadPool" << endl;
    move_to_busy(thread);
    thread->set_task(task);
}

